package approval

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/fisker/zjump-backend/internal/model"
	"gorm.io/gorm"
)

// DingTalkProvider 钉钉审批提供者
type DingTalkProvider struct {
	config  *model.ApprovalConfig
	baseURL string
	client  *http.Client
	db      *gorm.DB
}

// NewDingTalkProvider 创建钉钉审批提供者
func NewDingTalkProvider(config *model.ApprovalConfig, db *gorm.DB) *DingTalkProvider {
	// 使用用户配置的API基础URL，如果没有配置则使用默认值
	baseURL := config.APIBaseURL
	if baseURL == "" {
		baseURL = "https://oapi.dingtalk.com" // 默认值
	}

	return &DingTalkProvider{
		config:  config,
		baseURL: baseURL,
		client: &http.Client{
			Timeout: 30 * time.Second,
		},
		db: db,
	}
}

// CreateApproval 创建钉钉审批
func (p *DingTalkProvider) CreateApproval(ctx context.Context, approval *model.Approval) (string, error) {
	// 检查审批代码是否存在
	if p.config.ProcessCode == "" {
		return "", fmt.Errorf("审批代码未配置")
	}

	// 获取访问令牌
	token, err := p.getAccessToken(ctx)
	if err != nil {
		return "", fmt.Errorf("获取访问令牌失败: %v", err)
	}

	// 构建审批表单
	formContent := p.buildFormContent(approval)

	// 创建审批实例
	return p.createApprovalInstance(ctx, token, formContent, approval)
}

// getAccessToken 获取钉钉访问令牌
func (p *DingTalkProvider) getAccessToken(ctx context.Context) (string, error) {
	url := fmt.Sprintf("%s/gettoken?appkey=%s&appsecret=%s", p.baseURL, p.config.AppID, p.config.AppSecret)

	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		return "", err
	}

	resp, err := p.client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var result struct {
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
		Token   string `json:"access_token"`
	}

	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("解析响应失败: %v", err)
	}

	if result.ErrCode != 0 {
		return "", fmt.Errorf("钉钉API错误 [%d]: %s", result.ErrCode, result.ErrMsg)
	}

	return result.Token, nil
}

// buildFormContent 构建表单内容
func (p *DingTalkProvider) buildFormContent(approval *model.Approval) string {
	formData := []map[string]interface{}{
		{
			"name":  "title",
			"value": approval.Title,
		},
		{
			"name":  "description",
			"value": approval.Description,
		},
		{
			"name":  "reason",
			"value": approval.Reason,
		},
		{
			"name":  "resources",
			"value": fmt.Sprintf("%v", approval.ResourceNames),
		},
		{
			"name":  "duration",
			"value": fmt.Sprintf("%d", approval.Duration),
		},
	}

	jsonData, _ := json.Marshal(formData)
	return string(jsonData)
}

// createApprovalInstance 创建审批实例
func (p *DingTalkProvider) createApprovalInstance(ctx context.Context, token, formContent string, approval *model.Approval) (string, error) {
	// 使用数据库配置中的API路径，如果没有配置则使用默认路径
	apiPath := p.config.APIPath
	if apiPath == "" {
		apiPath = "/topapi/processinstance/create" // 默认路径
	}
	url := fmt.Sprintf("%s%s?access_token=%s", p.baseURL, apiPath, token)

	// 直接使用当前登录用户的用户名作为userID
	userID := approval.ApplicantID
	if userID == "" {
		userID = approval.ApplicantName // 如果ApplicantID为空，使用ApplicantName
	}
	deptID := "1" // 钉钉默认部门ID，可以根据需要调整

	// 从配置中读取审批人列表
	var approverIDs []string
	if p.config.ApproverUserIDs != "" {
		json.Unmarshal([]byte(p.config.ApproverUserIDs), &approverIDs)
	}

	reqBody := map[string]interface{}{
		"process_code":          p.config.ProcessCode,
		"originator_user_id":    userID,
		"form_component_values": json.RawMessage(formContent),
		"dept_id":               deptID,
	}

	// 如果配置了审批人，添加到请求体中
	if len(approverIDs) > 0 {
		reqBody["approvers"] = approverIDs
	}

	body, _ := json.Marshal(reqBody)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
	if err != nil {
		return "", err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := p.client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var result struct {
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
		Result  struct {
			ProcessInstanceID string `json:"process_instance_id"`
		} `json:"result"`
	}

	if err := json.Unmarshal(respBody, &result); err != nil {
		return "", fmt.Errorf("解析响应失败: %v", err)
	}

	if result.ErrCode != 0 {
		return "", fmt.Errorf("钉钉API错误 [%d]: %s", result.ErrCode, result.ErrMsg)
	}

	return result.Result.ProcessInstanceID, nil
}

// GetName 获取平台名称
func (p *DingTalkProvider) GetName() string {
	return "钉钉"
}

// GetApprovalStatus 获取审批状态
func (p *DingTalkProvider) GetApprovalStatus(ctx context.Context, externalID string) (*ApprovalStatusResponse, error) {
	// 获取访问令牌
	token, err := p.getAccessToken(ctx)
	if err != nil {
		return nil, fmt.Errorf("获取访问令牌失败: %v", err)
	}

	// 查询审批实例详情
	// 使用数据库配置中的API路径，如果没有配置则使用默认路径
	apiPathGet := p.config.APIPathGet
	if apiPathGet == "" {
		apiPathGet = "/topapi/processinstance/get" // 默认路径
	}
	url := fmt.Sprintf("%s%s?access_token=%s", p.baseURL, apiPathGet, token)

	reqBody := map[string]interface{}{
		"process_instance_id": externalID,
	}

	body, _ := json.Marshal(reqBody)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := p.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var result struct {
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
		Result  struct {
			Status string `json:"status"`
			Result string `json:"result"`
		} `json:"result"`
	}

	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, fmt.Errorf("解析响应失败: %v", err)
	}

	if result.ErrCode != 0 {
		return nil, fmt.Errorf("钉钉API错误 [%d]: %s", result.ErrCode, result.ErrMsg)
	}

	// 映射状态
	status := p.mapStatus(result.Result.Status)

	return &ApprovalStatusResponse{
		Status:  status,
		Comment: result.Result.Result,
	}, nil
}

// CancelApproval 取消审批
func (p *DingTalkProvider) CancelApproval(ctx context.Context, externalID string) error {
	// 获取访问令牌
	token, err := p.getAccessToken(ctx)
	if err != nil {
		return fmt.Errorf("获取访问令牌失败: %v", err)
	}

	// 取消审批实例
	// 使用数据库配置中的API路径，如果没有配置则使用默认路径
	apiPathCancel := p.config.APIPathCancel
	if apiPathCancel == "" {
		apiPathCancel = "/topapi/processinstance/cancel" // 默认路径
	}
	url := fmt.Sprintf("%s%s?access_token=%s", p.baseURL, apiPathCancel, token)

	reqBody := map[string]interface{}{
		"process_instance_id": externalID,
		"operator_userid":     p.config.AppID, // 使用应用ID作为操作人
	}

	body, _ := json.Marshal(reqBody)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(body))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")

	resp, err := p.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	var result struct {
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
	}

	if err := json.Unmarshal(respBody, &result); err != nil {
		return fmt.Errorf("解析响应失败: %v", err)
	}

	if result.ErrCode != 0 {
		return fmt.Errorf("钉钉API错误 [%d]: %s", result.ErrCode, result.ErrMsg)
	}

	return nil
}

// HandleCallback 处理回调
func (p *DingTalkProvider) HandleCallback(ctx context.Context, data interface{}) (*CallbackResult, error) {
	// 钉钉回调处理逻辑
	return nil, fmt.Errorf("钉钉回调处理未实现")
}

// ValidateConfig 验证配置
func (p *DingTalkProvider) ValidateConfig(config map[string]interface{}) error {
	// 验证钉钉配置
	return nil
}

// mapStatus 映射钉钉状态到系统状态
func (p *DingTalkProvider) mapStatus(dingTalkStatus string) model.ApprovalStatus {
	switch dingTalkStatus {
	case "RUNNING":
		return model.ApprovalStatusPending
	case "COMPLETED":
		return model.ApprovalStatusApproved
	case "TERMINATED":
		return model.ApprovalStatusRejected
	case "CANCELED":
		return model.ApprovalStatusCanceled
	default:
		return model.ApprovalStatusPending
	}
}
